#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
PDF文件合并工具（增强版）
功能：
1. 合并文件夹中的所有PDF文件
2. 提供进度条显示合并进度
3. 允许用户选择排序方式
4. 允许用户选择输出文件名
"""

import os
import sys
import re
import time
from PyPDF2 import PdfMerger, PdfReader
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.scrolledtext import ScrolledText
import threading

class PDFMergerApp:
    def __init__(self, root):
        """
        初始化应用程序
        """
        self.root = root
        self.root.title("PDF合并工具")
        self.root.geometry("600x500")
        self.root.resizable(True, True)
        
        # 设置最小窗口大小
        self.root.minsize(500, 400)
        
        # 如果是打包后的可执行文件，确定工作目录
        if getattr(sys, 'frozen', False):
            self.working_dir = os.path.dirname(sys.executable)
        else:
            self.working_dir = os.path.dirname(os.path.abspath(__file__))
        
        # 创建界面组件
        self.create_widgets()
        
        # 默认加载当前目录的PDF文件
        self.load_pdfs_from_dir(self.working_dir)
    
    def create_widgets(self):
        """
        创建UI组件
        """
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 目录选择部分
        dir_frame = ttk.Frame(main_frame)
        dir_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(dir_frame, text="PDF文件目录:").pack(side=tk.LEFT)
        
        self.dir_var = tk.StringVar(value=self.working_dir)
        ttk.Entry(dir_frame, textvariable=self.dir_var, width=50).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        ttk.Button(dir_frame, text="浏览...", command=self.browse_directory).pack(side=tk.LEFT)
        ttk.Button(dir_frame, text="刷新", command=self.refresh_pdfs).pack(side=tk.LEFT, padx=(5, 0))
        
        # 创建一个框架用于放置PDF文件列表和控制按钮
        list_control_frame = ttk.Frame(main_frame)
        list_control_frame.pack(fill=tk.BOTH, expand=True)
        
        # PDF文件列表标签
        ttk.Label(list_control_frame, text="PDF文件列表 (拖动调整顺序):").pack(anchor=tk.W)
        
        # 创建一个框架用于放置列表和滚动条
        list_frame = ttk.Frame(list_control_frame)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(5, 10))
        
        # 创建滚动条
        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 创建列表框
        self.pdf_listbox = tk.Listbox(list_frame, selectmode=tk.EXTENDED, height=10)
        self.pdf_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 配置滚动条和列表框的关联
        self.pdf_listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.pdf_listbox.yview)
        
        # 绑定拖放事件
        self.pdf_listbox.bind('<Button-1>', self.on_list_click)
        self.pdf_listbox.bind('<B1-Motion>', self.on_list_drag)
        
        # 控制按钮框架
        control_frame = ttk.Frame(list_control_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 排序按钮
        ttk.Button(control_frame, text="按名称排序", command=self.sort_by_name).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(control_frame, text="按数字排序", command=self.sort_by_number).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(control_frame, text="上移", command=self.move_up).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(control_frame, text="下移", command=self.move_down).pack(side=tk.LEFT)
        
        # 输出设置框架
        output_frame = ttk.Frame(main_frame)
        output_frame.pack(fill=tk.X, pady=(0, 10))
        
        ttk.Label(output_frame, text="输出文件名:").pack(side=tk.LEFT)
        
        self.output_var = tk.StringVar(value="合并文件")
        ttk.Entry(output_frame, textvariable=self.output_var, width=30).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        ttk.Label(output_frame, text=".pdf").pack(side=tk.LEFT)
        
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress = ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100)
        self.progress.pack(fill=tk.X, pady=(0, 10))
        
        # 状态信息
        self.status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(main_frame, textvariable=self.status_var)
        status_label.pack(anchor=tk.W)
        
        # 合并按钮
        self.merge_button = ttk.Button(main_frame, text="合并PDF文件", command=self.start_merge)
        self.merge_button.pack(pady=(10, 0), padx=5, fill=tk.X)
    
    def browse_directory(self):
        """
        浏览并选择目录
        """
        directory = filedialog.askdirectory(initialdir=self.dir_var.get())
        if directory:
            self.dir_var.set(directory)
            self.load_pdfs_from_dir(directory)
    
    def load_pdfs_from_dir(self, directory):
        """
        从指定目录加载PDF文件
        """
        try:
            # 获取目录中的所有PDF文件
            pdf_files = [f for f in os.listdir(directory) if f.lower().endswith('.pdf')]
            
            # 清空列表框
            self.pdf_listbox.delete(0, tk.END)
            
            # 将PDF文件添加到列表框
            for pdf in pdf_files:
                self.pdf_listbox.insert(tk.END, pdf)
            
            # 更新状态信息
            self.status_var.set(f"找到 {len(pdf_files)} 个PDF文件")
        except Exception as e:
            messagebox.showerror("错误", f"加载PDF文件时出错: {str(e)}")
            self.status_var.set("加载失败")
    
    def refresh_pdfs(self):
        """
        刷新PDF文件列表
        """
        self.load_pdfs_from_dir(self.dir_var.get())
    
    def natural_sort_key(self, s):
        """
        自然排序键函数
        """
        return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)]
    
    def sort_by_name(self):
        """
        按名称排序PDF文件
        """
        # 获取所有项目
        items = list(self.pdf_listbox.get(0, tk.END))
        # 按字母顺序排序
        items.sort()
        # 清空列表框
        self.pdf_listbox.delete(0, tk.END)
        # 重新添加排序后的项目
        for item in items:
            self.pdf_listbox.insert(tk.END, item)
        
        self.status_var.set("已按字母顺序排序")
    
    def sort_by_number(self):
        """
        按数字排序PDF文件（使用自然排序）
        """
        # 获取所有项目
        items = list(self.pdf_listbox.get(0, tk.END))
        # 按自然排序
        items.sort(key=self.natural_sort_key)
        # 清空列表框
        self.pdf_listbox.delete(0, tk.END)
        # 重新添加排序后的项目
        for item in items:
            self.pdf_listbox.insert(tk.END, item)
        
        self.status_var.set("已按自然顺序排序")
    
    def move_up(self):
        """
        将选中的项目上移
        """
        selected = self.pdf_listbox.curselection()
        if not selected or selected[0] == 0:
            return
        
        # 获取选中项目
        item = self.pdf_listbox.get(selected[0])
        # 删除选中项目
        self.pdf_listbox.delete(selected[0])
        # 在新位置插入项目
        self.pdf_listbox.insert(selected[0] - 1, item)
        # 选中移动后的项目
        self.pdf_listbox.selection_set(selected[0] - 1)
    
    def move_down(self):
        """
        将选中的项目下移
        """
        selected = self.pdf_listbox.curselection()
        if not selected or selected[0] == self.pdf_listbox.size() - 1:
            return
        
        # 获取选中项目
        item = self.pdf_listbox.get(selected[0])
        # 删除选中项目
        self.pdf_listbox.delete(selected[0])
        # 在新位置插入项目
        self.pdf_listbox.insert(selected[0] + 1, item)
        # 选中移动后的项目
        self.pdf_listbox.selection_set(selected[0] + 1)
    
    def on_list_click(self, event):
        """
        处理列表点击事件
        """
        self.drag_start_index = self.pdf_listbox.nearest(event.y)
    
    def on_list_drag(self, event):
        """
        处理列表拖动事件，实现项目重新排序
        """
        drag_end_index = self.pdf_listbox.nearest(event.y)
        
        if drag_end_index != self.drag_start_index:
            # 获取拖动的项目
            item = self.pdf_listbox.get(self.drag_start_index)
            # 删除原项目
            self.pdf_listbox.delete(self.drag_start_index)
            # 在新位置插入项目
            self.pdf_listbox.insert(drag_end_index, item)
            # 更新拖动起始位置
            self.drag_start_index = drag_end_index
    
    def start_merge(self):
        """
        开始合并PDF文件
        """
        # 获取PDF文件列表
        pdf_files = list(self.pdf_listbox.get(0, tk.END))
        
        if not pdf_files:
            messagebox.showwarning("警告", "没有PDF文件可合并!")
            return
        
        # 禁用合并按钮
        self.merge_button.config(state=tk.DISABLED)
        
        # 重置进度条
        self.progress_var.set(0)
        
        # 在新线程中执行合并操作
        threading.Thread(target=self.merge_pdfs, args=(pdf_files,), daemon=True).start()
    
    def merge_pdfs(self, pdf_files):
        """
        合并PDF文件
        """
        try:
            # 获取目录
            directory = self.dir_var.get()
            
            # 创建输出目录
            output_dir = os.path.join(directory, "output")
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
            
            # 设置输出文件名
            output_filename = self.output_var.get().strip()
            if not output_filename:
                output_filename = "合并文件"
            
            output_file = os.path.join(output_dir, f"{output_filename}.pdf")
            
            # 如果文件已存在，使用递增的文件名
            counter = 1
            while os.path.exists(output_file):
                output_file = os.path.join(output_dir, f"{output_filename}_{counter}.pdf")
                counter += 1
            
            # 创建 PdfMerger 对象
            merger = PdfMerger()
            
            # 总页数（用于计算进度）
            total_pages = 0
            for pdf in pdf_files:
                file_path = os.path.join(directory, pdf)
                reader = PdfReader(file_path)
                total_pages += len(reader.pages)
            
            # 已处理页数
            processed_pages = 0
            
            # 添加所有PDF文件
            for i, pdf in enumerate(pdf_files):
                # 更新状态
                self.status_var.set(f"正在处理: {pdf} ({i+1}/{len(pdf_files)})")
                
                file_path = os.path.join(directory, pdf)
                reader = PdfReader(file_path)
                
                # 添加文件
                merger.append(file_path)
                
                # 更新进度
                processed_pages += len(reader.pages)
                progress = (processed_pages / total_pages) * 100
                self.progress_var.set(progress)
                
                # 让UI有时间更新
                time.sleep(0.01)
            
            # 写入合并后的PDF文件
            self.status_var.set("正在保存合并后的PDF文件...")
            merger.write(output_file)
            merger.close()
            
            # 更新状态和进度
            self.progress_var.set(100)
            self.status_var.set(f"合并完成! 文件已保存为: {os.path.basename(output_file)}")
            
            # 在UI线程中显示成功消息和重新启用按钮
            self.root.after(0, lambda: self.merge_complete(os.path.basename(output_file)))
            
        except Exception as e:
            # 在UI线程中显示错误消息和重新启用按钮
            self.root.after(0, lambda: self.merge_error(str(e)))
    
    def merge_complete(self, filename):
        """
        合并完成后的处理
        """
        # 重新启用合并按钮
        self.merge_button.config(state=tk.NORMAL)
        
        # 显示成功消息
        messagebox.showinfo("成功", f"PDF文件已成功合并为: {filename}")
    
    def merge_error(self, error_msg):
        """
        合并出错后的处理
        """
        # 重新启用合并按钮
        self.merge_button.config(state=tk.NORMAL)
        
        # 重置进度条
        self.progress_var.set(0)
        
        # 更新状态
        self.status_var.set("合并失败")
        
        # 显示错误消息
        messagebox.showerror("错误", f"合并PDF时发生错误: {error_msg}")

def main():
    """
    主函数
    """
    # 创建主窗口
    root = tk.Tk()
    
    # 创建应用程序
    app = PDFMergerApp(root)
    
    # 运行主循环
    root.mainloop()

if __name__ == "__main__":
    main() 